﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using vmlModel;
using vmlModel.Entities;
using System.Windows.Media.Effects;
using System.Windows;

namespace XAMLFactory
{
    public class PathShapesBuilder
    {
        public UIElement CreatePath(vmlShape srcShp)
        {
            Path MainShape = new Path();
            Canvas.SetTop(MainShape, srcShp.MarginTop);
            Canvas.SetLeft(MainShape, srcShp.MarginLeft);
            Canvas.SetZIndex(MainShape, srcShp.Zindex);
            //MainShape.Width = srcShp.Width;
            //MainShape.Height = srcShp.Height;
            //// get data ///////////////
            string PathData = srcShp.Path;
            if (srcShp.ShapeType != null && srcShp.ShapeType.LiveAtrrs.Contains("path") && srcShp.ShapeType.Path != "")
            {
                PathData = srcShp.ShapeType.Path;
                srcShp.SubPaths = srcShp.ShapeType.SubPaths;
            }
            srcShp.PreparePathForDrawing();
            MainShape.Data = BuildPath(srcShp); // Geometry.Parse(GetPathData(PathData));

            /////////////////////////////
            MainShape.Fill = new System.Windows.Media.SolidColorBrush(srcShp.FillColor);
            MainShape.Stroke = new SolidColorBrush(srcShp.StrokeColor);
            MainShape.StrokeThickness = srcShp.StrokeWeight;
            if (srcShp.Stroke != null)
            {
                if (srcShp.Stroke.LiveAtrrs.Contains("weight")) MainShape.StrokeThickness = srcShp.Stroke.Weight;
                if (srcShp.Stroke.LiveAtrrs.Contains("color")) MainShape.Stroke = new SolidColorBrush(srcShp.Stroke.Color);
                MainShape.StrokeDashArray = srcShp.Stroke.vmlDashStyle;
                MainShape.Stroke.Opacity = srcShp.Stroke.Opacity;
                MainShape.StrokeLineJoin = srcShp.Stroke.vmlJoinStyle;
                MainShape.Stroke = new StrokeLineStyleBuilder().vmlRecLineStyle(srcShp);
            }
            if (srcShp.Fill != null)
            {
                MainShape.Fill = new FillBuilder().CreatevmlFill(srcShp); ;
            }
            if (srcShp.Shadow != null)
            {
                //Shadow
                DropShadowBitmapEffect dps = new DropShadowBitmapEffect();
                //dps.SetValue(NameProperty, "dps");
                dps.Softness = 0.1;
                dps.Noise = 0;
                dps.Opacity = srcShp.Shadow.Opacity;
                dps.ShadowDepth = srcShp.Shadow.ShadowDepth;
                dps.Direction = 135;
                dps.Color = srcShp.Shadow.Color;
                MainShape.BitmapEffect = dps;

            }
            //////////Transformation
            TransformGroup shpGrp = new TransformGroup();
            ///Scale/////////////////////
            ScaleTransform shpScl = new ScaleTransform(1,1);
            switch (srcShp.Flip)
            {
                case FlipDir.X:
                    shpScl = new ScaleTransform(-1, 1);
                    break;
                case FlipDir.Y:
                    shpScl = new ScaleTransform(1, -1);
                    break;
                case FlipDir.XY:
                    shpScl = new ScaleTransform(-1, -1);
                    break;
                default:
                    break;
            }
            shpGrp.Children.Add(shpScl);
            MainShape.RenderTransform = shpGrp;
            ///////////////////////////////
            return MainShape;
        }
        public static Geometry BuildPath(vmlShape srcShp)
        {
            // Create a StreamGeometry to use to specify myPath.
            StreamGeometry geometry = new StreamGeometry();
            geometry.FillRule = FillRule.EvenOdd;

            StringBuilder sb = new StringBuilder();
            // Open a StreamGeometryContext that can be used to describe this StreamGeometry 
            // object's contents.
            using (StreamGeometryContext ctx = geometry.Open())
            {
                foreach (var subPath in srcShp.SubPaths)
                {
                    Point CurrentPoint = new Point(0, 0);
                    foreach (var cmd in subPath.PathCommands)
                    {
                        switch (cmd.cmdName.ToLower())
                        {
                            case "m":
                            case "t":
                                ctx.BeginFigure(cmd.LastPoint, subPath.IsFilled /* is filled */,  subPath.IsClosed /* is closed */);
                                sb.AppendLine("BeginFigure at " + cmd.LastPoint.ToString() + "  is filled = " +  subPath.IsFilled.ToString() + " is closed = " + subPath.IsClosed.ToString());
                                break;
                            case "l":
                            case "r":
                                ctx.PolyLineTo(cmd.cmdPoints,subPath.IsStroked/* is stroked */, true /* is smooth join */);
                                //foreach (var pt in cmd.cmdPoints)
                                //{
                                //    ctx.LineTo(pt, subPath.IsStroked/* is stroked */, false /* is smooth join */);
                                //}    
                           
                            break;
                            case "c":
                            ctx.PolyBezierTo(cmd.cmdPoints, subPath.IsStroked, true);
                                break;
                            case "x":
                                break;
                            case "e":
                                break;
                            case "v":
                                break;
                            case "qx":
                                SweepDirection PathXDir = GetXPathDirection(CurrentPoint, cmd.cmdPoints[0]);
                                sb.AppendLine("---------QX------start---------------");
                                foreach (var pt in cmd.cmdPoints)
                                {
                                    sb.AppendLine("Current Point is " + CurrentPoint.ToString());
                                    sb.AppendLine("Goingto Point is " + pt.ToString());
                                    sb.AppendLine("size width is " + (pt.X - CurrentPoint.X).ToString());
                                    sb.AppendLine("size height is " + (pt.Y - CurrentPoint.Y).ToString());
                                    ctx.ArcTo(pt, new Size(Math.Abs(pt.X - CurrentPoint.X), Math.Abs(pt.Y - CurrentPoint.Y)), 0, false, PathXDir, true, false);
                                    CurrentPoint = pt;  
                               }
                                sb.AppendLine("---------QX----end-----------------");
                                break;
                            case "qy":
                                SweepDirection PathYDir = GetYPathDirection(CurrentPoint, cmd.cmdPoints[0]);

                                sb.AppendLine("---------QY------start---------------");
                                foreach (var pt in cmd.cmdPoints)
                                {
                                    sb.AppendLine("Current Point is " + CurrentPoint.ToString());
                                    sb.AppendLine("Goingto Point is " + pt.ToString());
                                    sb.AppendLine("size width is " + (pt.X - CurrentPoint.X).ToString());
                                    sb.AppendLine("size height is " + (pt.Y - CurrentPoint.Y).ToString());
                                    ctx.ArcTo(pt, new Size(Math.Abs(pt.X - CurrentPoint.X), Math.Abs(pt.Y - CurrentPoint.Y)), 0, false, PathYDir, true, false);
                                    CurrentPoint = pt;
                                }
                                sb.AppendLine("---------QY----end-----------------");
                                break;

                            case "nf":
                                break;
                            case "ns":
                                break;
                            case "ae":
                                break;
                            case "al":
                                break;
                            case "at":
                                break;
                            case "ar":
                                sb.AppendLine("---------AR------start---------------");
                                for (int i = 0; i < cmd.cmdPoints.Count; i += 4)
                                {
                                    Point LeftTop = cmd.cmdPoints[i];
                                    Point RightBttom = cmd.cmdPoints[i + 1];
                                    Point StartPoint = cmd.cmdPoints[i + 2];
                                    Point EndPoint = cmd.cmdPoints[i + 3];

                                    ctx.BeginFigure(StartPoint, subPath.IsFilled /* is filled */, subPath.IsClosed /* is closed */);
                                    sb.AppendLine("BeginFigure at " + StartPoint.ToString() + "  is filled = " + subPath.IsFilled.ToString() + " is closed = " + subPath.IsClosed.ToString());

                                    sb.AppendLine("Start Point is " + StartPoint.ToString());
                                    sb.AppendLine("Goingto Point is " + EndPoint.ToString());
                                    sb.AppendLine("size width is " + (RightBttom.X - LeftTop.X).ToString());
                                    sb.AppendLine("size height is " + (RightBttom.Y - LeftTop.Y).ToString());

                                    ctx.ArcTo(EndPoint, new Size(Math.Abs(RightBttom.X - LeftTop.X), Math.Abs(RightBttom.Y - LeftTop.Y)), 0, true , SweepDirection.Counterclockwise, true, false);
                                    CurrentPoint = EndPoint;
                                }
                                sb.AppendLine("---------AR----end-----------------");
                                break;
                            case "wa":
                                break;
                            case "wr":
                                sb.AppendLine("---------WR------start---------------");
                                for (int i = 0; i < cmd.cmdPoints.Count; i+= 4)
                                {
                                    Point LeftTop = cmd.cmdPoints[i];
                                    Point RightBttom = cmd.cmdPoints[i + 1];
                                    Point StartPoint = cmd.cmdPoints[i + 2];
                                    Point EndPoint = cmd.cmdPoints[i + 3];

                                    ctx.BeginFigure(StartPoint, subPath.IsFilled /* is filled */, subPath.IsClosed /* is closed */);
                                    sb.AppendLine("BeginFigure at " + StartPoint.ToString() + "  is filled = " + subPath.IsFilled.ToString() + " is closed = " + subPath.IsClosed.ToString());

                                    sb.AppendLine("Start Point is " + StartPoint.ToString());
                                    sb.AppendLine("Goingto Point is " + EndPoint.ToString());
                                    sb.AppendLine("size width is " + (RightBttom.X - LeftTop.X).ToString());
                                    sb.AppendLine("size height is " + (RightBttom.Y - LeftTop.Y).ToString());

                                    ctx.ArcTo(EndPoint, new Size(Math.Abs(RightBttom.X - LeftTop.X), Math.Abs(RightBttom.Y - LeftTop.Y)), 0, true , SweepDirection.Clockwise, true, false);
                                    CurrentPoint = EndPoint;
                                }
                                sb.AppendLine("---------WR----end-----------------");

                                break;
                            case "qb":
                                break;
                            default:
                                break;
                        }
                        CurrentPoint = cmd.LastPoint;
                        
                    }                
                }
                //global::System.Windows.Forms.MessageBox.Show(sb.ToString());
                
  
                    
            }
            
            // Freeze the geometry (make it unmodifiable)
            // for additional performance benefits.
            geometry.Freeze();

           return  geometry;

        }

        
        /// <summary>
        /// Convert a VML v:shapetype/@path string to a WPF Path data string
        /// </summary>
        /// <param name="vmlPath">a VML path like m@4@5l@4@11@9@11@9@5xe
        /// see http://www.w3.org/TR/NOTE-VML#_Toc416858391
        /// </param>
        /// <returns>a WPF path like this: m 4,5 l 4,11 9,11 9,5 z</returns>
        public static string GetPathData(string vmlPath)
        {

            var commandKeys = new string[] { "nf", "ns", "ae", "al", "at", "ar", "wa", "wr", "qx", "qy", "qb", "m", "l", "c", "x", "e", "t", "r", "v" };

            string path = vmlPath.Replace('@', ' ');

            foreach (var commandKey in commandKeys)
            {
                path = path.Replace(commandKey, " " + commandKey);
            }

            string[] elements = path.Split(' ');

            StringBuilder builder = new StringBuilder();

            for (int i = 0; i < elements.Length; i++)
            {
                switch (elements[i])
                {
                    case "m":
                        builder.AppendFormat("m {0},{1} ", elements[i + 1], elements[i + 2]);
                        i += 2;
                        break;

                    case "l":
                        builder.Append("l ");
                        i++;
                        do
                        {
                            builder.AppendFormat("{0},{1} ", elements[i], elements[i + 1]);

                            i += 2;
                        }
                        while (!commandKeys.Contains(elements[i]));
                        i--;

                        break;

                    case "x":
                        builder.Append("z");
                        break;

                    case "e":
                        break;
                }
            }

            string wpfPathData = builder.ToString();


            return wpfPathData;
        }
        // Emad M Raghib 16-4
        public static SweepDirection GetXPathDirection(Point Pt1 , Point Pt2)
        { 
           //if (Pt2.X > Pt1.X) return SweepDirection.Clockwise; 
           // else{
           //     return SweepDirection.Counterclockwise;
           // 
            return SweepDirection.Counterclockwise;

        }
        public static SweepDirection GetYPathDirection(Point Pt1, Point Pt2)
        {
            //if (Pt2.Y > Pt1.Y) return SweepDirection.Clockwise;
            //else
            //{
                return SweepDirection.Counterclockwise;
           // }

        }

    }
}
